<template>
  <beautiful-chat
      :participants="userInfo.account=='admin'?state.participants2:state.participants1"
      :titleImageUrl="state.titleImageUrl"
      :onMessageWasSent="onMessageWasSent"
      :messageList="state.messageList"
      :newMessagesCount="state.newMessagesCount"
      :isOpen="state.isChatOpen"
      :close="closeChat"
      :icons="state.icons"
      :open="openChat"
      :showEmoji="true"
      :showFile="true"
      :showEdition="false"
      :showDeletion="false"
      :deletionConfirmation="true"
      :showTypingIndicator="state.showTypingIndicator"
      :showLauncher="true"
      :showCloseButton="true"
      :colors="state.colors"
      :alwaysScrollToBottom="state.alwaysScrollToBottom"
      :disableUserListToggle="false"
      :messageStyling="state.messageStyling"
      @onType="handleOnType"
      @edit="editMessage">
    <template v-slot:header>
      🤔 Good chat between
      {{ (userInfo.account == 'admin' ? state.participants2 : state.participants1).map(m => m.name).join(' & ') }}
    </template>
    <template v-slot:system-message-body="{ message }">
      [System]: {{ message.text }}
    </template>
  </beautiful-chat>
</template>

<script lang="ts" setup name='CustomChat'>
import {} from 'vue'
import {ElMessage} from "_element-plus@2.2.32@element-plus";
import useUserInfo from "../../store/module/userInfo";
import pinia from "../../store";
import {v4 as uuidv4} from 'uuid';
import {FileService} from '@/api/file/fileUpDown'

let useUserInfoStore = useUserInfo(pinia);
let userInfo = useUserInfoStore.userInfo;
const state = reactive<any>({
  websocket: undefined, //websocket实例
  heartTimer: undefined, //心跳定时器实例
  socketHeart: 0, //心跳次数
  HeartTimeOut: 3000, //心跳超时时间
  socketError: 0, //错误次数

  participants: [
    {
      id: 'mattmezza',
      name: 'Matteo',
      imageUrl: 'https://avatars3.githubusercontent.com/u/1915989?s=230&v=4',
    }

  ],
  participants1: [
    {
      id: 'admin',
      name: '超级管理员',
      imageUrl: 'https://avatars3.githubusercontent.com/u/1915989?s=230&v=4',
    },
  ],
  participants2: [
    {
      id: 'lida',
      name: '李达',
      imageUrl: 'https://avatars3.githubusercontent.com/u/37018832?s=200&v=4'
    }

  ],
  titleImageUrl: 'https://a.slack-edge.com/66f9/img/avatars-teams/ava_0001-34.png',
  messageList: [
    // {type: 'text', author: `me`, id: 0, data: {text: `Why don't they have salsa on the table?`}},
    // {type: 'text', author: `mattmezza`, id: 1, data: {text: `What do you need salsa for?`}},
    // {type: 'text', author: `me`, id: 2, data: {text: `Salsa is now the number one condiment in America.`}},
    // {
    //   type: 'text',
    //   author: `mattmezza`,
    //   id: 3,
    //   data: {text: `You know why? Because people like to say 'salsa.' 'Excuse me, do you have salsa?' 'We need more salsa.' 'Where is the salsa? No salsa?'`}
    // },
    // {
    //   type: 'text',
    //   author: `me`,
    //   id: 4,
    //   data: {text: `You know it must be impossible for a Spanish person to order seltzer and not get salsa. 'I wanted seltzer, not salsa.'`}
    // },
    // {
    //   type: 'text',
    //   author: `mattmezza`,
    //   id: 5,
    //   data: {text: `Don't you know the difference between seltzer and salsa?? You have the seltezer after the salsa!`}
    // },
    // {type: 'text', author: `me`, id: 6, data: {text: `See, this should be a show. This is the show. `}},
    // {type: 'text', author: `mattmezza`, id: 7, data: {text: `What?`}},
    // {type: 'text', author: `me`, id: 8, data: {text: `This. Just talking.`}},
    // {type: 'text', author: `mattmezza`, id: 9, data: {text: `Yeah, right.`}},
    // {type: 'text', author: `me`, id: 10, data: {text: `I'm really serious. I think that's a good idea. `}},
    // {type: 'text', author: `mattmezza`, id: 11, data: {text: `Just talking? Well what's the show about?`}},
    // {type: 'text', author: `me`, id: 12, data: {text: `It's about nothing.`}},
    // {type: 'text', author: `mattmezza`, id: 100, data: {text: `No story?`}},
    // {type: 'system', id: 13, data: {text: 'You have been transferred to another operator', meta: '04-07-2018 15:57'}},
    // {
    //   type: 'file',
    //   author: `support`,
    //   id: 14,
    //   data: {
    //     text: `No forget the story. `,
    //     file: {name: 'awesome', url: 'https://media.giphy.com/media/dkGhBWE3SyzXW/giphy.gif'}
    //   }
    // },
    // {
    //   type: 'file',
    //   author: `me`,
    //   id: 15,
    //   data: {
    //     text: `What about this one instead?? `,
    //     file: {url: 'http://www.quickmeme.com/img/2d/2d95cc80f9a2a2578a8f632eebecddcc1c12e5b08ab85f81a5d401670d5f36c1.jpg'},
    //     meta: '✓✓ Read'
    //   }
    // },
    // {
    //   type: 'text',
    //   author: `support`,
    //   id: 16,
    //   data: {text: `You've got to have a story. You've got to have a story. You've got to have a story. You've got to have a story. You've got to have a story. You've got to have a story. `}
    // },
    // {type: 'emoji', author: `me`, id: 17, data: {emoji: `😋`}},
    // {type: 'text', author: `me`, id: 18, data: {text: `Do you read me...`, meta: '✓✓ Read'}},
    // {type: 'text', author: `me`, id: 19, data: {text: `...or not?`, meta: '✓ Delivered'}},
    // {type: 'system', id: 20, data: {text: 'User changed security key', meta: '04-08-2018 15:57'}},
    // {
    //   type: 'text',
    //   author: `support`,
    //   id: 21,
    //   data: {text: `What about suggestions?`},
    //   suggestions: ["Looks good!", "It's OK.", "Uhh.. Do I really have to say something?", "This suggestion is way too long for css purpose. Let's make it long... Longer, and more and more.. Never ending."]
    // }
  ],
  newMessagesCount: 0,
  isChatOpen: false,
  showTypingIndicator: '',//一个字符串，可以设置为用户的participant.id，为用户显示typing指示符
  colors: {
    header: {
      bg: '#4e8cff',
      text: '#ffffff'
    },
    launcher: {
      bg: '#4e8cff'
    },
    messageList: {
      bg: '#ffffff'
    },
    sentMessage: {
      bg: '#4e8cff',
      text: '#ffffff'
    },
    receivedMessage: {
      bg: '#eaeaea',
      text: '#222222'
    },
    userInput: {
      bg: '#f4f7f9',
      text: '#565867'
    }
  },
  alwaysScrollToBottom: false, //当设置为true时，当有新事件时总是将聊天滚动到底部(新消息，用户开始输入…)
  messageStyling: true //启用*粗体* / emh /下划线等
})

// const sendMessage =  (text: any)=> {
//   if (text.length > 0) {
//     state.newMessagesCount = state.isChatOpen ? state.newMessagesCount : state.newMessagesCount + 1
//     onMessageWasSent({ author: 'support', type: 'text', data: { text } })
//   }
// }
/**
 * @description 发送消息
 */
const onMessageWasSent = async (message: any) => {
  console.log("message", message)
  let uuid = uuidv4(); //消息id
  message.id = uuid
  message.data.meta = Meta.BEING_SEND //消息状态
  let toMessageId = userInfo.account == 'admin' ? state.participants2[0].id : state.participants1[0].id //消息接受人
  let msg: any = {
    type: Type.MESSAGE_REQUEST,
    params: {
      uuid: uuid,
      message: null,
      toMessageId: toMessageId,
      messageType: message.type,
      isAck: false,
      fileName: null,
      fileUrl: null
    }
  }
  switch (message.type) {
    case MessageType.EMOJI:
      msg.params.message = message.data.emoji
      break;
    case MessageType.FILE:
      //先上传
      const formData = new FormData();
      formData.append("file", message.data.file)
      await FileService.upload(formData)
          .then(({data}) => {
            console.log(`上传 ${data.resultObj?.fileName} 成功！`)
            msg.params.fileName = data.resultObj?.fileName
            message.data.file = {}
            //message.data.file.name = data.resultObj?.fileName
            msg.params.fileUrl = import.meta.env.VITE_BASE_URL + data.resultObj?.fileUrl
            message.data.file.url = import.meta.env.VITE_BASE_URL + data.resultObj?.fileUrl
          })
      break;
    case MessageType.TEXT:
      msg.params.message = message.data.text
      break;
    default:
      break
  }
  state.messageList = [...state.messageList, message]
  state.websocket.send(JSON.stringify(msg))
}
const openChat = () => {
  // called when the user clicks on the fab button to open the chat
  state.isChatOpen = true
  state.newMessagesCount = 0
}
const closeChat = () => {
  // called when the user clicks on the button to close the chat
  state.isChatOpen = false
}
const handleScrollToTop = () => {
  // called when the user scrolls message list to top
  // leverage pagination for loading another page of messages
}
const handleOnType = () => {
  console.log('Emit typing event')
}
const editMessage = (message: any) => {
  const m = state.messageList.find((m: { id: any }) => m.id === message.id);
  m.isEdited = true;
  m.data.text = message.data.text;
}


/**
 * @description 创建实例
 */
const connectSocket = () => {
  //const wsUrl = `ws://localhost:9999/websocket/`
  const wsUrl = `ws://localhost:19999` //netty

  if ('WebSocket' in window) {
    //return new WebSocket(wsUrl + userInfo.account);
    return new WebSocket(wsUrl);
  } else {
    ElMessage.error('Not support websocket')
    throw new Error("Not support websocket")
  }
}

/**
 * @description 初始化 socket
 */
const initWebSocket = () => {
  state.websocket = connectSocket();
  websocketOnopen();
  websocketOnmessage();
  websocketOnerror();
  websocketClose();
};

/**
 * @description socket 连接成功
 * socket连接 连接成功 1 秒后, 将用户信息注册到服务器在线用户表
 */
const websocketOnopen = () => {
  state.websocket.onopen = function (event: any) {
    setTimeout(() => {
      if (state.websocket.readyState == WebSocket.OPEN) {
        let data = {
          type: Type.REGISTER_REQUEST, //注册请求
          params: userInfo,
        }
        state.websocket.send(JSON.stringify(data));
        console.log("连接 websocket 成功");
        resetHeart();
      } else {
        ElMessage.error('Websocket连接没有开启')
      }
    }, 1000)
  };


};

/**
 * @description socket 连接失败
 */
const websocketOnerror = () => {
  state.websocket.onerror = function () {
    console.log("连接 websocket 失败");
  };
};

/**
 * @description socket 断开链接
 */
const websocketClose = () => {
  state.websocket.onclose = function () {
    console.log("断开连接");
  };
};

enum Type {
  MESSAGE_REQUEST = 1,//单聊发送
  MESSAGE_RESPONSE = 2,//单聊响应
  CREATE_GROUP_REQUEST = 3,//创建群
  CREATE_GROUP_RESPONSE = 4,//创建群响应
  LOGIN_REQUEST = 5,//登录请求
  LOGIN_RESPONSE = 6,// 登录响应
  REGISTER_REQUEST = 7, //注册请求
  REGISTER_RESPONSE = 8,//注册响应
  GROUP_MESSAGE_REQUEST = 9, //发送群消息
  GROUP_MESSAGE_RESPONSE = 10,//接收群消息
  HEARTBEAT_REQUEST = 11,//心跳消息请求
  HEARTBEAT_RESPONSE = 12,//心跳消息恢复
}

enum MessageType {
  TEXT = 'text',
  EMOJI = 'emoji',
  FILE = 'file',
}

enum Meta {
  READ = '✓✓ 已读',
  DELIVERED = '✓ 已送达',
  BEING_SEND = '正在发送...',
  SEND_FAIL = '发送失败!'
}

// 响应封装
interface MessagePacket {
  status: number,
  type: number,
  params: {
    uuid: string,
    message: string,
    fromUser: {
      account: string
    },
    toUser: {
      account: string
    },
    messageType: string
    meta: string
    isAck: boolean
    fileName: string
    fileUrl: string
  }
}

/**
 * @description socket 处理收到单聊的信息
 * {type: 'text', author: `me`, id: 2, data: {text: `Salsa is now the number one condiment in America.`}},
 * {type: 'text', author: `me`, id: 18, data: {text: `Do you read me...`, meta: '✓✓ Read'}},
 * {type: 'text', author: `me`, id: 19, data: {text: `...or not?`, meta: '✓ Delivered'}},
 * {type: 'emoji', author: `me`, id: 17, data: {emoji: `😋`}},
 */
const handleSingleMessage = (data: MessagePacket) => {
  let meta = data.params!.meta;
  let uuid = data.params!.uuid;
  let isAck = data.params!.isAck;
  if (isAck) {
    if (meta) {
      let exist: any[] = state.messageList.filter((i: any) => {
        if (i.id == uuid) return i
      });
      if (exist && exist.length > 0) {
        if (exist[0].author == 'me') {
          if (exist[0].data.meta != Meta.READ) {
            exist[0].data.meta = meta;
          }
        }
      }
    }
  } else {
    //封装消息
    let messageType = data.params.messageType;
    let msg: any = {
      type: messageType,
      author: data.params.fromUser.account,
      id: uuid,
      data: {
        file: {}
      }
    }
    switch (messageType) {
      case MessageType.EMOJI:
        msg.data.emoji = data.params.message
        break;
      case MessageType.FILE:
        //msg.data.file.name = data.params.fileName
        msg.data.file.url = data.params.fileUrl
        msg.data.text = data.params.message
        break;
      case MessageType.TEXT:
        msg.data.text = data.params.message
        break;
      default:
        break
    }

    state.messageList.push(msg)
    if (!state.isChatOpen) {
      state.newMessagesCount = state.newMessagesCount + 1
    }
    let responseMsg = {
      type: Type.MESSAGE_REQUEST,
      params: {
        uuid: uuid,
        message: '返回响应',
        toMessageId: data.params.fromUser.account,
        messageType: data.params.messageType,
        meta: Meta.DELIVERED,
        isAck: true
      },
    }
    state.websocket.send(JSON.stringify(responseMsg))
  }
}
const handleCreateChatResponse = (data: any) => {

}
const handleGroupMessageResponse = (data: any) => {

}

/**
 * @description socket 接收数据
 */
const websocketOnmessage = () => {
  state.websocket.onmessage = function (event: any) {
    let data = JSON.parse(event.data);
    if (data.status == 200) {
      switch (data.type) {
        case Type.MESSAGE_RESPONSE:
          handleSingleMessage(data);
          break;
        case Type.CREATE_GROUP_RESPONSE:
          handleCreateChatResponse(data);
          break;
        case Type.GROUP_MESSAGE_RESPONSE: //群聊消息接受 其实 也是适配单聊
          handleGroupMessageResponse(data);
          break;
        case Type.HEARTBEAT_RESPONSE:
          console.log("收到心跳检测回复")
          resetHeart()
          break;
        default:
          break;
      }
    }
    console.log("收到服务端socket消息", event.data);

  };
};

/**
 * @description socket 发送数据
 */
const sendMsg = (data: any) => {
  state.websocket.send(data);
};

/**
 * @description socket 重置心跳
 */
const resetHeart = () => {
  state.socketHeart = 0;
  state.socketError = 0;
  clearInterval(state.heartTimer);
  sendSocketHeart();
};

/**
 * @description socket 心跳发送
 */
const sendSocketHeart = () => {
  state.heartTimer = setInterval(() => {
    if (state.socketHeart <= 2) {
      console.log("心跳发送: ", state.socketHeart);
      state.websocket.send(JSON.stringify({
        type: Type.HEARTBEAT_REQUEST,
        params: {}
      }));
      state.socketHeart = state.socketHeart + 1;
    } else {
      reconnect()
    }
  }, state.HeartTimeOut);
};

/**
 * @description socket 重连
 */
const reconnect = () => {
  if (state.socketError <= 2) {
    clearInterval(state.heartTimer);
    initWebSocket();
    state.socketError = state.socketError + 1;
    console.log("socket重连", state.socketError);
  } else {
    console.log("重试次数已用完的逻辑", state.socketError);
    clearInterval(state.heartTimer);
  }
};

onMounted(() => {
  initWebSocket()
})
</script>

<style scoped lang='less'>

</style>
